Passed
Push — master ( c14eae...514642 )
by EMP
01:16
created

main.js ➔ displayFile   B

Complexity

Conditions 4

Size

Total Lines 65
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 53
dl 0
loc 65
rs 8.5381
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
"use strict";
2
3
sodium.ready.then(function() {
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
4
5
const ae = new AllEars(function(ok) {
1 ignored issue
show
Bug introduced by
The variable AllEars seems to be never declared. If this is a global, consider adding a /** global: AllEars */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6
	if (ok) {
7
		const greeting = localStorage.greeting;
1 ignored issue
show
Bug introduced by
The variable localStorage seems to be never declared. If this is a global, consider adding a /** global: localStorage */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
8
		if (greeting) {
9
			document.getElementById("greeting").textContent = greeting;
10
			document.getElementById("txt_pg").value = greeting;
11
		}
12
13
		document.getElementById("txt_skey").style.background = "#466";
14
		document.getElementById("txt_skey").maxLength = "64";
15
	} else {
16
		console.log("Failed to load All-Ears");
17
	}
18
});
19
20
function TabState(cur, max, btnDele, btnUpdt) {
21
	this.cur = cur;
22
	this.max = max;
23
	this.btnDele = btnDele;
24
	this.btnUpdt = btnUpdt;
25
}
26
27
const tabs = [
28
	new TabState(0, 0, false, true), // Inbox
29
	new TabState(0, 0, false, true), // Outbx
30
	new TabState(0, 2, true, false), // Write
31
	new TabState(0, 2, false, false), // Notes
32
	new TabState(0, 3, false, true) // Tools
33
];
34
35
let showHeaders = false;
36
37
let tab = 0;
38
const TAB_INBOX = 0;
39
const TAB_DRBOX = 1;
40
const TAB_WRITE = 2;
41
const TAB_NOTES = 3;
42
const TAB_TOOLS = 4;
43
44
// Helper functions
45
function getCountryName(countryCode) {
46
	switch (countryCode) {
47
		case "DZ": return "Algeria";
48
		case "AO": return "Angola";
49
		case "BJ": return "Benin";
50
		case "BW": return "Botswana";
51
		case "BF": return "Burkina Faso";
52
		case "BI": return "Burundi";
53
		case "CV": return "Cabo Verde";
54
		case "CM": return "Cameroon";
55
		case "CF": return "Central African Republic";
56
		case "TD": return "Chad";
57
		case "KM": return "Comoros";
58
		case "CD": return "Congo";
59
		case "DJ": return "Djibouti";
60
		case "EG": return "Egypt";
61
		case "GQ": return "Equatorial Guinea";
62
		case "ER": return "Eritrea";
63
		case "SZ": return "Eswatini";
64
		case "ET": return "Ethiopia";
65
		case "GA": return "Gabon";
66
		case "GM": return "Gambia";
67
		case "GH": return "Ghana";
68
		case "GW": return "Guinea-Bissau";
69
		case "GN": return "Guinea";
70
		case "CI": return "Ivory Coast";
71
		case "KE": return "Kenya";
72
		case "LS": return "Lesotho";
73
		case "LR": return "Liberia";
74
		case "LY": return "Libya";
75
		case "MG": return "Madagascar";
76
		case "MW": return "Malawi";
77
		case "ML": return "Mali";
78
		case "MR": return "Mauritania";
79
		case "MU": return "Mauritius";
80
		case "YT": return "Mayotte";
81
		case "MA": return "Morocco";
82
		case "MZ": return "Mozambique";
83
		case "NA": return "Namibia";
84
		case "NE": return "Niger";
85
		case "NG": return "Nigeria";
86
		case "CG": return "Republic of the Congo";
87
		case "RW": return "Rwanda";
88
		case "RE": return "Réunion";
89
		case "SH": return "Saint Helena";
90
		case "SN": return "Senegal";
91
		case "SC": return "Seychelles";
92
		case "SL": return "Sierra Leone";
93
		case "SO": return "Somalia";
94
		case "ZA": return "South Africa";
95
		case "SS": return "South Sudan";
96
		case "SD": return "Sudan";
97
		case "ST": return "São Tomé and Príncipe";
98
		case "TZ": return "Tanzania";
99
		case "TG": return "Togo";
100
		case "TN": return "Tunisia";
101
		case "UG": return "Uganda";
102
		case "EH": return "Western Sahara";
103
		case "ZM": return "Zambia";
104
		case "ZW": return "Zimbabwe";
105
		case "AQ": return "Antarctica";
106
		case "BV": return "Bouvet Island";
107
		case "TF": return "French Southern Territories";
108
		case "HM": return "Heard Island and McDonald Islands";
109
		case "GS": return "South Georgia and the South Sandwich Islands";
110
		case "AF": return "Afghanistan";
111
		case "AM": return "Armenia";
112
		case "AZ": return "Azerbaijan";
113
		case "BH": return "Bahrain";
114
		case "BD": return "Bangladesh";
115
		case "BT": return "Bhutan";
116
		case "IO": return "British Indian Ocean Territory";
117
		case "BN": return "Brunei";
118
		case "KH": return "Cambodia";
119
		case "CN": return "China";
120
		case "CC": return "Cocos [Keeling] Islands";
121
		case "GE": return "Georgia";
122
		case "JO": return "Hashemite Kingdom of Jordan";
123
		case "HK": return "Hong Kong";
124
		case "IN": return "India";
125
		case "ID": return "Indonesia";
126
		case "IR": return "Iran";
127
		case "IQ": return "Iraq";
128
		case "IL": return "Israel";
129
		case "JP": return "Japan";
130
		case "KZ": return "Kazakhstan";
131
		case "KW": return "Kuwait";
132
		case "KG": return "Kyrgyzstan";
133
		case "LA": return "Laos";
134
		case "LB": return "Lebanon";
135
		case "MO": return "Macao";
136
		case "MY": return "Malaysia";
137
		case "MV": return "Maldives";
138
		case "MN": return "Mongolia";
139
		case "MM": return "Myanmar";
140
		case "NP": return "Nepal";
141
		case "KP": return "North Korea";
142
		case "OM": return "Oman";
143
		case "PK": return "Pakistan";
144
		case "PS": return "Palestine";
145
		case "PH": return "Philippines";
146
		case "QA": return "Qatar";
147
		case "SA": return "Saudi Arabia";
148
		case "SG": return "Singapore";
149
		case "KR": return "South Korea";
150
		case "LK": return "Sri Lanka";
151
		case "SY": return "Syria";
152
		case "TW": return "Taiwan";
153
		case "TJ": return "Tajikistan";
154
		case "TH": return "Thailand";
155
		case "TR": return "Turkey";
156
		case "TM": return "Turkmenistan";
157
		case "AE": return "United Arab Emirates";
158
		case "UZ": return "Uzbekistan";
159
		case "VN": return "Vietnam";
160
		case "YE": return "Yemen";
161
		case "AL": return "Albania";
162
		case "AD": return "Andorra";
163
		case "AT": return "Austria";
164
		case "BY": return "Belarus";
165
		case "BE": return "Belgium";
166
		case "BA": return "Bosnia and Herzegovina";
167
		case "BG": return "Bulgaria";
168
		case "HR": return "Croatia";
169
		case "CY": return "Cyprus";
170
		case "CZ": return "Czechia";
171
		case "DK": return "Denmark";
172
		case "EE": return "Estonia";
173
		case "FO": return "Faroe Islands";
174
		case "FI": return "Finland";
175
		case "FR": return "France";
176
		case "DE": return "Germany";
177
		case "GI": return "Gibraltar";
178
		case "GR": return "Greece";
179
		case "GG": return "Guernsey";
180
		case "HU": return "Hungary";
181
		case "IS": return "Iceland";
182
		case "IE": return "Ireland";
183
		case "IM": return "Isle of Man";
184
		case "IT": return "Italy";
185
		case "JE": return "Jersey";
186
		case "XK": return "Kosovo";
187
		case "LV": return "Latvia";
188
		case "LI": return "Liechtenstein";
189
		case "LU": return "Luxembourg";
190
		case "MT": return "Malta";
191
		case "MC": return "Monaco";
192
		case "ME": return "Montenegro";
193
		case "NL": return "Netherlands";
194
		case "MK": return "North Macedonia";
195
		case "NO": return "Norway";
196
		case "PL": return "Poland";
197
		case "PT": return "Portugal";
198
		case "LT": return "Republic of Lithuania";
199
		case "MD": return "Republic of Moldova";
200
		case "RO": return "Romania";
201
		case "RU": return "Russia";
202
		case "SM": return "San Marino";
203
		case "RS": return "Serbia";
204
		case "SK": return "Slovakia";
205
		case "SI": return "Slovenia";
206
		case "ES": return "Spain";
207
		case "SJ": return "Svalbard and Jan Mayen";
208
		case "SE": return "Sweden";
209
		case "CH": return "Switzerland";
210
		case "UA": return "Ukraine";
211
		case "GB": return "United Kingdom";
212
		case "VA": return "Vatican City";
213
		case "AX": return "Åland";
214
		case "AI": return "Anguilla";
215
		case "AG": return "Antigua and Barbuda";
216
		case "AW": return "Aruba";
217
		case "BS": return "Bahamas";
218
		case "BB": return "Barbados";
219
		case "BZ": return "Belize";
220
		case "BM": return "Bermuda";
221
		case "BQ": return "Bonaire, Sint Eustatius, and Saba";
222
		case "VG": return "British Virgin Islands";
223
		case "CA": return "Canada";
224
		case "KY": return "Cayman Islands";
225
		case "CR": return "Costa Rica";
226
		case "CU": return "Cuba";
227
		case "CW": return "Curaçao";
228
		case "DM": return "Dominica";
229
		case "DO": return "Dominican Republic";
230
		case "SV": return "El Salvador";
231
		case "GL": return "Greenland";
232
		case "GD": return "Grenada";
233
		case "GP": return "Guadeloupe";
234
		case "GT": return "Guatemala";
235
		case "HT": return "Haiti";
236
		case "HN": return "Honduras";
237
		case "JM": return "Jamaica";
238
		case "MQ": return "Martinique";
239
		case "MX": return "Mexico";
240
		case "MS": return "Montserrat";
241
		case "NI": return "Nicaragua";
242
		case "PA": return "Panama";
243
		case "PR": return "Puerto Rico";
244
		case "BL": return "Saint Barthélemy";
245
		case "LC": return "Saint Lucia";
246
		case "MF": return "Saint Martin";
247
		case "PM": return "Saint Pierre and Miquelon";
248
		case "VC": return "Saint Vincent and the Grenadines";
249
		case "SX": return "Sint Maarten";
250
		case "KN": return "St Kitts and Nevis";
251
		case "TT": return "Trinidad and Tobago";
252
		case "TC": return "Turks and Caicos Islands";
253
		case "VI": return "U.S. Virgin Islands";
254
		case "US": return "United States";
255
		case "AS": return "American Samoa";
256
		case "AU": return "Australia";
257
		case "CX": return "Christmas Island";
258
		case "CK": return "Cook Islands";
259
		case "TL": return "Democratic Republic of Timor-Leste";
260
		case "FM": return "Federated States of Micronesia";
261
		case "FJ": return "Fiji";
262
		case "PF": return "French Polynesia";
263
		case "GU": return "Guam";
264
		case "KI": return "Kiribati";
265
		case "MH": return "Marshall Islands";
266
		case "NR": return "Nauru";
267
		case "NC": return "New Caledonia";
268
		case "NZ": return "New Zealand";
269
		case "NU": return "Niue";
270
		case "NF": return "Norfolk Island";
271
		case "MP": return "Northern Mariana Islands";
272
		case "PW": return "Palau";
273
		case "PG": return "Papua New Guinea";
274
		case "PN": return "Pitcairn Islands";
275
		case "WS": return "Samoa";
276
		case "SB": return "Solomon Islands";
277
		case "TK": return "Tokelau";
278
		case "TO": return "Tonga";
279
		case "TV": return "Tuvalu";
280
		case "UM": return "U.S. Minor Outlying Islands";
281
		case "VU": return "Vanuatu";
282
		case "WF": return "Wallis and Futuna";
283
		case "AR": return "Argentina";
284
		case "BO": return "Bolivia";
285
		case "BR": return "Brazil";
286
		case "CL": return "Chile";
287
		case "CO": return "Colombia";
288
		case "EC": return "Ecuador";
289
		case "FK": return "Falkland Islands";
290
		case "GF": return "French Guiana";
291
		case "GY": return "Guyana";
292
		case "PY": return "Paraguay";
293
		case "PE": return "Peru";
294
		case "SR": return "Suriname";
295
		case "UY": return "Uruguay";
296
		case "VE": return "Venezuela";
297
	}
0 ignored issues
show
Comprehensibility introduced by
There is no default case in this switch, so nothing gets returned when all cases fail. You might want to consider adding a default or return undefined explicitly.
Loading history...
298
}
299
300
function getCountryFlag(countryCode) {
301
	return sodium.to_string(new Uint8Array([
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
302
		240, 159, 135, 166 + countryCode.codePointAt(0) - 65,
303
		240, 159, 135, 166 + countryCode.codePointAt(1) - 65
304
	]));
305
}
306
307
function getMsgId(num) {
308
	let i;
309
	if (ae.GetExtMsgHeaders(num).toLowerCase().slice(0, 11) === "message-id:") {
310
		i = 0;
311
	} else {
312
		i = ae.GetExtMsgHeaders(num).toLowerCase().indexOf("\nmessage-id:");
313
		if (i < 1) return "ERR";
314
		i++;
315
	}
316
317
	const x = ae.GetExtMsgHeaders(num).slice(i + 11).trim();
318
	if (x[0] !== "<") return "ERR2";
319
	return x.slice(1, x.indexOf(">"));
320
}
321
322
function clearDisplay() {
323
	let el = document.getElementById("midright").getElementsByTagName("img");
324
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("audio");
325
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("video");
326
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("embed");
327
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("iframe");
328
	if (el.length !== 1) return;
329
330
	URL.revokeObjectURL(el[0].src);
1 ignored issue
show
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
331
	el[0].remove();
332
}
333
334
function displayFile(num) {
335
	clearDisplay();
336
337
	document.getElementById("midright").scroll(0, 0);
338
	document.getElementById("midright").setAttribute("data-msgid", ae.GetUplMsgIdHex(num));
339
	document.getElementById("btn_reply").disabled = true;
340
	document.getElementById("btn_mdele").disabled = false;
341
	document.getElementById("midright").children[0].hidden = true;
342
	document.getElementById("midright").children[1].textContent = ae.GetUplMsgTitle(num);
343
344
	switch (ae.GetUplMsgType(num)) {
345
		case "text": {
346
			document.getElementById("midright").children[2].hidden = false;
347
			document.getElementById("midright").children[2].textContent = sodium.to_string(ae.GetUplMsgBody(num));
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
348
		break;}
349
350
		case "image": {
351
			document.getElementById("midright").children[2].hidden = true;
352
			const img = document.createElement("img");
353
			img.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
2 ignored issues
show
Bug introduced by
The variable Blob seems to be never declared. If this is a global, consider adding a /** global: Blob */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
354
			document.getElementById("midright").appendChild(img);
355
356
			img.onclick = function() {
357
				if (!document.fullscreen)
358
					img.requestFullscreen();
359
				else
360
					document.exitFullscreen();
361
			};
362
		break;}
363
364
		case "audio": {
365
			document.getElementById("midright").children[2].hidden = true;
366
			const el = document.createElement("audio");
367
			el.controls = "controls";
368
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
369
			document.getElementById("midright").appendChild(el);
370
		break;}
371
372
		case "video": {
373
			document.getElementById("midright").children[2].hidden = true;
374
			const el = document.createElement("video");
375
			el.controls = "controls";
376
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
377
			document.getElementById("midright").appendChild(el);
378
		break;}
379
380
		case "pdf": {
381
			document.getElementById("midright").children[2].hidden = true;
382
			const el = document.createElement("embed");
383
			el.type = "application/pdf";
384
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer], {type: "application/pdf"}));
385
			document.getElementById("midright").appendChild(el);
386
		break;}
387
388
		case "html": {
389
			document.getElementById("midright").children[2].hidden = true;
390
			const el = document.createElement("iframe");
391
			el.allow = "";
392
			el.sandbox = "";
393
			el.csp = "base-uri 'none'; child-src 'none'; connect-src 'none'; default-src 'none'; font-src 'none'; form-action 'none'; frame-ancestors 'none'; frame-src 'none'; img-src 'none'; manifest-src 'none'; media-src 'none'; object-src 'none'; script-src 'none'; style-src 'none'; worker-src 'none';";
394
			el.srcdoc = sodium.to_string(ae.GetUplMsgBody(num).buffer);
395
			document.getElementById("midright").appendChild(el);
396
		break;}
397
	}
398
}
399
400
function displayMsg(isInt, num) {
401
	clearDisplay();
402
403
	document.getElementById("btn_mdele").disabled = false;
404
	document.getElementById("midright").scroll(0, 0);
405
	document.getElementById("midright").setAttribute("data-msgid", isInt? ae.GetIntMsgIdHex(num) : ae.GetExtMsgIdHex(num));
406
407
	const ts = isInt? ae.GetIntMsgTime(num) : ae.GetExtMsgTime(num);
408
409
	document.getElementById("btn_reply").disabled = false;
410
	document.getElementById("btn_reply").onclick = function() {
411
		document.getElementById("write_recv").value = isInt? ae.GetIntMsgFrom(num) : ae.GetExtMsgReplyAddress(num);
412
		document.getElementById("write_subj").value = (isInt ? ae.GetIntMsgTitle(num) : ae.GetExtMsgTitle(num));
413
		if (!document.getElementById("write_subj").value.startsWith("Re:")) document.getElementById("write_subj").value = "Re: " + document.getElementById("write_subj").value;
414
		document.querySelector("#write2_pkey > input").value = isInt ? ae.GetIntMsgFromPk(num) : "";
415
416
		document.getElementById("write_recv").readOnly = !isInt;
417
		document.getElementById("write_subj").readOnly = !isInt;
418
		document.getElementById("write_subj").setAttribute("data-replyid", isInt? "" : getMsgId(num));
419
420
		document.getElementById("btn_write").click();
421
		document.getElementById("div_write_1").hidden = false;
422
		document.getElementById("div_write_2").hidden = true;
423
		document.getElementById("write_body").focus();
424
		for (const opt of document.getElementById("write_from").options) {
425
			if (opt.value === (isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num))) {
426
				opt.selected = true;
427
			}
428
		}
429
	};
430
431
	document.getElementById("midright").children[0].hidden = false;
432
	document.getElementById("midright").children[2].hidden = false;
433
434
	if (isInt) {
435
		document.getElementById("midright").children[1].textContent = ae.GetIntMsgTitle(num);
436
		document.getElementById("midright").children[2].textContent = ae.GetIntMsgBody(num);
437
	} else {
438
		document.getElementById("midright").children[2].innerHTML = "";
439
440
		const headers = document.createElement("p");
441
		headers.textContent = ae.GetExtMsgHeaders(num);
442
		headers.className = "mono";
443
		headers.hidden = !showHeaders;
444
		document.getElementById("midright").children[2].appendChild(headers);
445
446
		const body = document.createElement("p");
447
		body.textContent = ae.GetExtMsgBody(num);
448
		document.getElementById("midright").children[2].appendChild(body);
449
450
		document.getElementById("midright").children[1].textContent = ae.GetExtMsgTitle(num);
451
		document.getElementById("midright").children[1].onclick = function() {showHeaders = !showHeaders; headers.hidden = !showHeaders;};
452
		document.getElementById("midright").children[1].style.cursor = "pointer";
453
	}
454
455
	document.getElementById("readmsg_envto").textContent = isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num);
456
457
	const tzOs = new Date().getTimezoneOffset();
458
	const tz = ((tzOs < 0) ? "+" : "-") + Math.floor(tzOs / -60).toString().padStart(2, "0") + (tzOs % 60 * -1).toString().padStart(2, "0");
459
	document.getElementById("readmsg_date").children[0].textContent = new Date((ts * 1000) + (tzOs * -60000)).toISOString().slice(0, 19).replace("T", " ") + " " + tz;
460
461
	if (!isInt) {
462
		document.getElementById("readmsg_ip").hidden = false;
463
		document.getElementById("readmsg_country").hidden = false;
464
		document.getElementById("readmsg_tls").hidden = false;
465
		document.getElementById("readmsg_greet").hidden = false;
466
467
		const cc = ae.GetExtMsgCountry(num);
468
469
		document.getElementById("readmsg_ip").children[0].textContent = ae.GetExtMsgIp(num);
470
		document.getElementById("readmsg_country").textContent = getCountryFlag(cc) + " " + getCountryName(cc);
471
		document.getElementById("readmsg_tls").children[0].textContent = ae.GetExtMsgTLS(num);
472
		document.getElementById("readmsg_greet").children[0].textContent = ae.GetExtMsgGreet(num);
473
		document.getElementById("readmsg_envfrom").textContent = ae.GetExtMsgFrom(num);
474
475
		let flagText = "";
476
		if (!ae.GetExtMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
477
		if (!ae.GetExtMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
478
		if (!ae.GetExtMsgFlagPExt(num)) flagText += "<abbr title=\"The sender did not use the Extended (ESMTP) protocol\">SMTP</abbr> ";
479
		if (!ae.GetExtMsgFlagQuit(num)) flagText += "<abbr title=\"The sender did not issue the required QUIT command\">QUIT</abbr> ";
480
		if (ae.GetExtMsgFlagRare(num)) flagText += "<abbr title=\"The sender issued unusual command(s)\">RARE</abbr> ";
481
		if (ae.GetExtMsgFlagFail(num)) flagText += "<abbr title=\"The sender issued invalid command(s)\">FAIL</abbr> ";
482
		if (ae.GetExtMsgFlagPErr(num)) flagText += "<abbr title=\"The sender violated the protocol\">PROT</abbr> ";
483
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
484
	} else {
485
		document.getElementById("readmsg_ip").hidden = true;
486
		document.getElementById("readmsg_country").hidden = true;
487
		document.getElementById("readmsg_greet").hidden = true;
488
489
		document.getElementById("readmsg_tls").hidden = false;
490
		document.getElementById("readmsg_tls").textContent = ae.GetIntMsgFromPk(num);
491
492
		let symbol = "<span title=\"Invalid level\">&#x26a0;</span>";
493
		if (ae.GetIntMsgFrom(num) === "system") {if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"System\">&#x1f162;</span>";} // S (System)
494
		else if (ae.GetIntMsgLevel(num) === 0) symbol = "<span title=\"Level 0 User\">&#x1f10c;</span>"; // 0
495
		else if (ae.GetIntMsgLevel(num) === 1) symbol = "<span title=\"Level 1 User\">&#x278a;</span>"; // 1
496
		else if (ae.GetIntMsgLevel(num) === 2) symbol = "<span title=\"Level 2 User\">&#x278b;</span>"; // 2
497
		else if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"Administrator\">&#x1f150;</span>"; // A (Admin)
498
		document.getElementById("readmsg_envfrom").innerHTML = symbol + " " + ae.GetIntMsgFrom(num);
499
500
		let flagText = "";
501
		if (!ae.GetIntMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
502
		if (!ae.GetIntMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
503
		if (ae.GetIntMsgFlagE2ee(num)) flagText += "<abbr title=\"End-to-end encrypted\">E2EE</abbr> ";
504
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
505
	}
506
}
507
508
// Interface
509
function addMsg(isInt, i) {
510
	const row = document.getElementById("tbl_inbox").insertRow(-1);
511
	row.setAttribute("data-msgid", isInt? ae.GetIntMsgIdHex(i) : ae.GetExtMsgIdHex(i));
512
513
	const cellTime = row.insertCell(-1);
514
	const cellSubj = row.insertCell(-1);
515
	const cellSnd1 = row.insertCell(-1);
516
	const cellSnd2 = row.insertCell(-1);
517
518
	const ts = isInt? ae.GetIntMsgTime(i) : ae.GetExtMsgTime(i);
519
	cellTime.setAttribute("data-ts", ts);
520
	cellTime.textContent = new Date((ts * 1000) + (new Date().getTimezoneOffset() * -60000)).toISOString().slice(0, 10);
521
522
	cellSubj.textContent = isInt? ae.GetIntMsgTitle(i) : ae.GetExtMsgTitle(i);
523
524
	if (isInt) {
525
		cellSnd1.textContent = ae.GetIntMsgFrom(i);
526
		cellSnd1.className = (ae.GetIntMsgFrom(i).length === 16) ? "mono" : "";
527
	} else {
528
		const from1 = ae.GetExtMsgFrom(i);
529
		const from2 = from1.substring(from1.indexOf("@") + 1);
530
		const cc = ae.GetExtMsgCountry(i);
531
532
		cellSnd1.textContent = from1.substring(0, from1.indexOf("@"));
533
534
		const flag = document.createElement("abbr");
535
		flag.textContent = getCountryFlag(cc);
536
		flag.title = getCountryName(cc);
537
		cellSnd2.appendChild(flag);
538
539
		const fromText = document.createElement("span");
540
		fromText.textContent = " " + from2;
541
		cellSnd2.appendChild(fromText);
542
	}
543
544
	row.onclick = function() {
545
		displayMsg(isInt, i);
546
	};
547
}
548
549
function getRowsPerPage() {
550
	const tbl = document.getElementById("tbl_inbox");
551
	tbl.innerHTML = "";
552
	const row = tbl.insertRow(-1);
553
	const cell = row.insertCell(-1);
554
	cell.textContent = "0";
555
556
	const rowsPerPage = Math.floor(getComputedStyle(document.getElementById("div_inbox")).height.replace("px", "") / getComputedStyle(document.querySelector("#tbl_inbox > tbody > tr:first-child")).height.replace("px", "")) - 1; // -1 allows space for 'load more'
557
	tbl.innerHTML = "";
558
	return rowsPerPage;
559
}
560
561
function addMessages() {
562
	const rowsPerPage = getRowsPerPage();
563
	let skipMsgs = rowsPerPage * tabs[TAB_INBOX].cur;
564
565
	const maxExt = ae.GetExtMsgCount();
566
	const maxInt = ae.GetIntMsgCount();
567
568
	tabs[TAB_INBOX].max = Math.floor((maxExt + maxInt - 1) / rowsPerPage);
569
570
	let numExt = 0;
571
	let numInt = 0;
572
	let numAdd = 0;
573
574
	while (numAdd < rowsPerPage) {
575
		const tsInt = (numInt < maxInt) ? ae.GetIntMsgTime(numInt) : -1;
576
		const tsExt = (numExt < maxExt) ? ae.GetExtMsgTime(numExt) : -1;
577
		if (tsInt === -1 && tsExt === -1) break;
578
579
		if (tsInt !== -1 && (tsExt === -1 || tsInt > tsExt)) {
580
			if (skipMsgs > 0) skipMsgs--; else {addMsg(true, numInt); numAdd++;}
581
			numInt++;
582
		} else if (tsExt !== -1) {
583
			if (skipMsgs > 0) skipMsgs--; else {addMsg(false, numExt); numAdd++;}
584
			numExt++;
585
		}
586
	}
587
588
	if (ae.GetReadyMsgBytes() < ae.GetTotalMsgBytes()) {
589
		const inbox = document.getElementById("tbl_inbox");
590
		const row = inbox.insertRow(-1);
591
		const cell = row.insertCell(-1);
592
		cell.textContent = "Load more (" + (ae.GetTotalMsgBytes() - ae.GetReadyMsgBytes()) / 1024 + " KiB left)";
593
594
		row.onclick = function() {
595
			this.onclick = "";
596
597
			ae.Message_Browse(false, false, function(successBrowse) {
598
				document.getElementById("tbl_inbox").style.opacity = 1;
599
600
				if (successBrowse) {
601
					addMessages();
602
					addUploads();
603
					addSent();
604
					if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
605
				}
606
			});
607
		};
608
	}
609
}
610
611
function addUploads() {
612
	const tbl = document.getElementById("tbd_uploads");
613
	tbl.innerHTML = "";
614
615
	for (let i = 0; i < ae.GetUplMsgCount(); i++) {
616
		const row = tbl.insertRow(-1);
617
		row.setAttribute("data-msgid", ae.GetUplMsgIdHex(i));
618
619
		let cell;
620
		cell = row.insertCell(-1); cell.textContent = new Date(ae.GetUplMsgTime(i) * 1000).toISOString().slice(0, 10);
621
622
		cell = row.insertCell(-1); cell.textContent = ae.GetUplMsgTitle(i);
623
		cell.onclick = function() {displayFile(this.parentElement.rowIndex - 1);};
624
625
		cell = row.insertCell(-1); cell.textContent = (ae.GetUplMsgBytes(i) / 1024).toFixed(1);
626
627
		cell = row.insertCell(-1);
628
		if (ae.GetUplMsgIdHex(i)) {
629
			cell.innerHTML = "<button data-msgid=\"" + ae.GetUplMsgIdHex(i) + "\" type=\"button\">X</button>";
630
631
			cell.children[0].onclick = function() {
632
				const tr = this.parentElement.parentElement;
633
				ae.Message_Delete(this.getAttribute("data-msgid"), function(success) {
634
					if (success) tr.remove();
635
				});
636
			};
637
		}
638
	}
639
}
640
641
function displayOutMsg(num) {
642
	clearDisplay();
643
	document.getElementById("midright").scroll(0, 0);
644
	document.getElementById("midright").setAttribute("data-msgid", ae.GetOutMsgIdHex(num));
645
	document.getElementById("btn_reply").disabled = true;
646
	document.getElementById("btn_mdele").disabled = false;
647
	document.getElementById("midright").children[0].hidden = false;
648
	document.getElementById("midright").children[2].hidden = false;
649
650
	document.getElementById("midright").children[1].textContent = ae.GetOutMsgSubj(num);
651
	document.getElementById("midright").children[2].textContent = ae.GetOutMsgBody(num);
652
653
	document.getElementById("readmsg_envto").textContent = ae.GetOutMsgTo(num);
654
	document.getElementById("readmsg_envfrom").textContent = ae.GetOutMsgFrom(num);
655
656
	const ts = ae.GetOutMsgTime(num);
657
	const tzOs = new Date().getTimezoneOffset();
658
	const tz = ((tzOs < 0) ? "+" : "-") + Math.floor(tzOs / -60).toString().padStart(2, "0") + (tzOs % 60 * -1).toString().padStart(2, "0");
659
	document.getElementById("readmsg_date").children[0].textContent = new Date((ts * 1000) + (tzOs * -60000)).toISOString().slice(0, 19).replace("T", " ") + " " + tz;
660
661
	const isInt = ae.GetOutMsgIsInt(num);
662
	document.getElementById("readmsg_ip").hidden      = isInt;
663
	document.getElementById("readmsg_country").hidden = isInt;
664
	document.getElementById("readmsg_tls").hidden     = isInt;
665
	document.getElementById("readmsg_greet").hidden   = isInt;
666
667
	if (!isInt) {
668
//		const cc = ae.GetExtMsgCountry(num);
669
670
		document.getElementById("readmsg_ip").children[0].textContent = ae.GetOutMsgIp(num);
671
//		document.getElementById("readmsg_country").textContent = getCountryFlag(cc) + " " + getCountryName(cc);
672
//		document.getElementById("readmsg_tls").children[0].textContent = ae.GetOutMsgTLS(num);
673
		document.getElementById("readmsg_greet").children[0].textContent = ae.GetOutMsgGreet(num);
674
	}
675
676
	let flagText = "";
677
	if (!ae.GetOutMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
678
	if (!ae.GetOutMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
679
	if (ae.GetOutMsgFlagE2ee(num)) flagText += "<abbr title=\"End-to-end encrypted\">E2EE</abbr> ";
680
	document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
681
}
682
683
function addSent() {
684
	const tbl = document.getElementById("tbl_drbox");
685
	tbl.innerHTML = "";
686
687
	for (let i = 0; i < ae.GetOutMsgCount(); i++) {
688
		const row = tbl.insertRow(-1);
689
		row.setAttribute("data-msgid", ae.GetOutMsgIdHex(i));
690
691
		let cell;
692
		cell = row.insertCell(-1); cell.textContent = new Date(ae.GetOutMsgTime(i) * 1000).toISOString().slice(0, 10);
693
		cell = row.insertCell(-1); cell.textContent = ae.GetOutMsgSubj(i);
694
		row.onclick = function() {displayOutMsg(i);};
695
	}
696
}
697
698
function updateAddressCounts() {
699
	document.getElementById("limit_normal").textContent = (ae.GetAddressCountNormal() + "/" + ae.GetLimitNormalA(ae.GetUserLevel())).padStart(ae.GetLimitNormalA(ae.GetUserLevel()) > 9 ? 5 : 1);
700
	document.getElementById("limit_shield").textContent = (ae.GetAddressCountShield() + "/" + ae.GetLimitShieldA(ae.GetUserLevel())).padStart(ae.GetLimitShieldA(ae.GetUserLevel()) > 9 ? 5 : 1);
701
	document.getElementById("limit_total").textContent = ((ae.GetAddressCountNormal() + ae.GetAddressCountShield()) + "/" + ae.GetAddrPerUser()).padStart(5);
702
}
703
704
function adjustLevel(pubkey, level, c) {
705
	const fs = document.getElementById("fs_accs");
706
	fs.disabled = true;
707
708
	ae.Account_Update(pubkey, level, function(success) {
709
		fs.disabled = false;
710
711
		if (success) {
712
			c[4].textContent = level;
713
			c[5].children[0].disabled = (level === 3);
714
			c[6].children[0].disabled = (level === 0);
715
		}
716
	});
717
}
718
719
function addAccountToTable(i) {
720
	const tblAccs = document.getElementById("tbd_accs");
721
	const row = tblAccs.insertRow(-1);
722
	let cell;
723
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserPkHex(i);
724
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSpace(i);
725
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserNAddr(i);
726
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSAddr(i);
727
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserLevel(i);
728
729
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">+</button>";
730
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) + 1, c);};
731
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 3);
732
733
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">&minus;</button>";
734
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) - 1, c);};
735
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 0);
736
737
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">X</button>";
738
	cell.children[0].onclick = function() {
739
		const tr = this.parentElement.parentElement;
740
		ae.Account_Delete(tr.cells[0].textContent, function(success) {
741
			if (success) tr.remove();
742
		});
743
	};
744
}
745
746
function reloadAccount() {
747
	// Limits
748
	const tblLimits = document.getElementById("tbl_limits");
749
	if (ae.IsUserAdmin()) {
750
		for (let i = 0; i < 4; i++) {
751
			tblLimits.rows[i].cells[1].children[0].disabled = false;
752
			tblLimits.rows[i].cells[2].children[0].disabled = false;
753
			tblLimits.rows[i].cells[3].children[0].disabled = false;
754
755
			tblLimits.rows[i].cells[1].children[0].value = ae.GetLimitStorage(i) + 1;
756
			tblLimits.rows[i].cells[2].children[0].value = ae.GetLimitNormalA(i);
757
			tblLimits.rows[i].cells[3].children[0].value = ae.GetLimitShieldA(i);
758
		}
759
	} else {
760
		const lvl = ae.GetUserLevel();
761
		tblLimits.rows[lvl].cells[1].children[0].value = ae.GetLimitStorage(lvl) + 1;
762
		tblLimits.rows[lvl].cells[2].children[0].value = ae.GetLimitNormalA(lvl);
763
		tblLimits.rows[lvl].cells[3].children[0].value = ae.GetLimitShieldA(lvl);
764
	}
765
766
	// Accounts
767
	const tblAccs = document.getElementById("tbd_accs");
768
769
	// All: Our account
770
	const row = tblAccs.insertRow(-1);
771
	let cell;
772
	cell = row.insertCell(-1); cell.textContent = ae.GetUserPkHex();
773
	cell = row.insertCell(-1); cell.textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
774
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountNormal();
775
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountShield();
776
	cell = row.insertCell(-1); cell.textContent = ae.GetUserLevel();
777
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\" disabled=\"disabled\">+</button>";
778
779
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_downme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">&minus;</button>";
780
	cell.children[0].onclick = function() {
781
		const newLevel = parseInt(row.cells[4].textContent) - 1;
782
		ae.Account_Update(ae.GetUserPkHex(), newLevel, function(success) {
783
			if (success) row.cells[4].textContent = newLevel;
784
		});
785
	};
786
787
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_killme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">X</button>";
788
	cell.children[0].onclick = function() {
789
		ae.Account_Delete(ae.GetUserPkHex(), function(success) {
790
			if (success) row.remove();
791
		});
792
	};
793
794
	document.getElementById("txt_reg").disabled = !ae.IsUserAdmin();
795
	document.getElementById("btn_reg").disabled = !ae.IsUserAdmin();
796
797
	// Contacts
798
	for (let i = 0; i < ae.GetContactCount(); i++) {
799
		addContact(
800
			ae.GetContactMail(i),
801
			ae.GetContactName(i),
802
			ae.GetContactNote(i)
803
		);
804
	}
805
806
	// Addresses
807
	for (let i = 0; i < ae.GetAddressCount(); i++) {
808
		addAddress(i);
809
	}
810
811
	updateAddressCounts();
812
	addMessages();
813
	addUploads();
814
	addSent();
815
816
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
817
}
818
819
function deleteAddress(addr) {
820
	let btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
821
	for (let i = 0; i < btns.length; i++) btns[i].disabled = true;
822
823
	let addressToDelete = -1;
824
825
	for (let i = 0; i < ae.GetAddressCount(); i++) {
826
		if (addr === ae.GetAddress(i)) {
827
			addressToDelete = i;
828
			break;
829
		}
830
	}
831
832
	if (addressToDelete === -1) return;
833
834
	ae.Address_Delete(addressToDelete, function(success) {
835
		if (success) {
836
			document.getElementById("tbl_addrs").deleteRow(addressToDelete);
837
			document.getElementById("write_from").remove(addressToDelete);
838
			updateAddressCounts();
839
840
			if (ae.GetAddressCountNormal() < ae.GetLimitNormalA(ae.GetUserLevel())) document.getElementById("btn_address_create_normal").disabled = false;
841
			if (ae.GetAddressCountShield() < ae.GetLimitShieldA(ae.GetUserLevel())) document.getElementById("btn_address_create_shield").disabled = false;
842
843
			ae.Private_Update(function(success2) {
844
				if (!success2) console.log("Failed to update the Private field");
845
846
				btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
847
				for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
848
			});
849
		} else {
850
			console.log("Failed to delete address");
851
852
			btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
853
			for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
854
		}
855
	});
856
}
857
858 View Code Duplication
function shieldMix(addr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
859
	let newAddr = "";
860
861
	for (let i = 0; i < 16; i++) {
862
		switch (addr.charAt(i)) {
863
			case '1':
864
				newAddr += "1iIlL".charAt(Math.floor(Math.random() * 5));
865
				break;
866
			case '0':
867
				newAddr += "0oO".charAt(Math.floor(Math.random() * 3));
868
				break;
869
			case 'w':
870
				newAddr += "VvWw".charAt(Math.floor(Math.random() * 4));
871
				break;
872
			default:
873
				newAddr += (Math.random() > 0.5) ? addr.charAt(i) : addr.charAt(i).toUpperCase();
874
		}
875
	}
876
877
	return newAddr;
878
}
879
880
function addAddress(num) {
881
	const addrTable = document.getElementById("tbl_addrs");
882
	const row = addrTable.insertRow(-1);
883
	const cellAddr = row.insertCell(-1);
884
	const cellChk1 = row.insertCell(-1);
885
	const cellChk2 = row.insertCell(-1);
886
	const cellBtnD = row.insertCell(-1);
887
888
	cellAddr.textContent = ae.GetAddress(num);
889
	cellAddr.onclick = function() {
890
		if (cellAddr.textContent.length === 16)
891
			navigator.clipboard.writeText(shieldMix(cellAddr.textContent) + "@" + ae.GetDomainEml());
1 ignored issue
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
892
		else
893
			navigator.clipboard.writeText(cellAddr.textContent + "@" + ae.GetDomainEml());
894
	};
895
896
	cellChk1.innerHTML = ae.GetAddressAccExt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
897
	cellChk2.innerHTML = ae.GetAddressAccInt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
898
899
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
900
	cellBtnD.onclick = function() {deleteAddress(cellAddr.textContent);};
901
902
	const opt = document.createElement("option");
903
	opt.value = cellAddr.textContent;
904
	opt.textContent = cellAddr.textContent + "@" + ae.GetDomainEml();
905
	document.getElementById("write_from").appendChild(opt);
906
}
907
908
document.getElementById("btn_dele").onclick = function() {
909
	this.blur();
910
911
	if (tab === TAB_WRITE) {
912
		tabs[tab].cur = 0;
913
		updateTab();
914
915
		document.getElementById("write_recv").value = "";
916
		document.getElementById("write_subj").value = "";
917
		document.getElementById("write_body").value = "";
918
919
		document.getElementById("write_recv").readOnly = false;
920
		document.getElementById("write_subj").readOnly = false;
921
		document.getElementById("write_subj").setAttribute("data-replyid", "");
922
923
		document.getElementById("write_recv").focus();
924
	}
925
};
926
927
document.getElementById("btn_updt").onclick = function() {
928
	const btn = this;
929
	btn.disabled = true;
930
	btn.blur();
931
932
	if (tab === TAB_INBOX) {
933
		document.getElementById("tbl_inbox").style.opacity = 0.5;
934
935
		ae.Message_Browse(true, false, function(successBrowse) {
936
			document.getElementById("tbl_inbox").style.opacity = 1;
937
938
			if (successBrowse) {
939
				addMessages();
940
				addUploads();
941
				btn.disabled = false;
942
			} else {
943
				console.log("Failed to refresh");
944
				btn.disabled = false;
945
			}
946
		});
947
	}
948
};
949
950
document.getElementById("btn_mdele").onclick = function() {
951
	const btn = this;
952
	btn.blur();
953
	btn.disabled = true;
954
955
	const delId = document.getElementById("midright").getAttribute("data-msgid");
956
	if (!delId) return;
957
958
	ae.Message_Delete(delId, function(success) {
959
		if (success) {
960
			["tbl_inbox", "tbl_drbox", "tbd_uploads"].forEach(function(tbl_name) {
961
				const tbl = document.getElementById(tbl_name);
962
				for (let i = 0; i < tbl.rows.length; i++) {if (tbl.rows[i].getAttribute("data-msgid") === delId) tbl.deleteRow(i);}
963
			});
964
965
			addMessages();
966
			addUploads();
967
			addSent();
968
		} else btn.disabled = false;
969
	});
970
};
971
972
function addContact(mail, name, note) {
973
	const tbl = document.getElementById("tbl_ctact");
974
	const row = tbl.insertRow(-1);
975
	const cellMail = row.insertCell(-1);
976
	const cellName = row.insertCell(-1);
977
	const cellNote = row.insertCell(-1);
978
	const cellBtnD = row.insertCell(-1);
979
980
	cellMail.textContent = mail;
981
	cellName.textContent = name;
982
	cellNote.textContent = note;
983
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
984
985
	cellMail.contentEditable = true;
986
	cellName.contentEditable = true;
987
	cellNote.contentEditable = true;
988
989
	cellBtnD.onclick = function() {row.remove();};
990
}
991
992
document.getElementById("btn_newcontact").onclick = function() {
993
	addContact("", "", "");
994
};
995
996
document.getElementById("btn_savecontacts").onclick = function() {
997
	while (ae.GetContactCount() > 0) {
998
		ae.DeleteContact(0);
999
	}
1000
1001
	for (const row of document.getElementById("tbl_ctact").rows) {
1002
		ae.AddContact(row.cells[0].textContent, row.cells[1].textContent, row.cells[2].textContent);
1003
	}
1004
1005
	const btn = this;
1006
	btn.disabled = true;
1007
1008
	ae.Private_Update(function(success) {
1009
		btn.disabled = false;
1010
1011
		if (!success) {
1012
			console.log("Failed contacts update");
1013
		}
1014
	});
1015
};
1016
1017
function writeVerify() {
1018
	document.getElementById("div_write_1").hidden = true;
1019
	document.getElementById("div_write_2").hidden = false;
1020
1021
	document.getElementById("write2_recv").textContent = document.getElementById("write_recv").value;
1022
	document.getElementById("write2_subj").textContent = document.getElementById("write_subj").value;
1023
	document.getElementById("write2_rply").textContent = document.getElementById("write_subj").getAttribute("data-replyid");
1024
	document.getElementById("write2_body").textContent = document.getElementById("write_body").value;
1025
1026
	if (document.getElementById("write_recv").value.indexOf("@") >= 0) {
1027
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value + "@" + ae.GetDomainEml();
1028
		document.getElementById("write2_pkey").hidden = true;
1029
	} else {
1030
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value;
1031
		document.getElementById("write2_pkey").hidden = false;
1032
	}
1033
}
1034
1035
function updateTab() {
1036
	switch (tab) {
1037
		case TAB_INBOX:
1038
			addMessages();
1039
		break;
1040
1041
		case TAB_DRBOX:
1042
			addSent();
1043
		break;
1044
1045
		case TAB_WRITE:
1046
			switch (tabs[tab].cur) {
1047
				case 0: // Write
1048
					document.getElementById("div_write_1").hidden = false;
1049
					document.getElementById("div_write_2").hidden = true;
1050
					document.getElementById("write_body").focus();
1051
				break;
1052
1053
				case 1: // Verify
1054
					writeVerify();
1055
				break;
1056
1057
				case 2: // Send
1058
					ae.Message_Create(
1059
						document.getElementById("write_subj").value,
1060
						document.getElementById("write_body").value,
1061
						document.getElementById("write_from").value,
1062
						document.getElementById("write_recv").value,
1063
						document.getElementById("write_subj").getAttribute("data-replyid"),
1064
						(document.getElementById("write2_recv").textContent.indexOf("@") > 0) ? null : sodium.from_base64(document.querySelector("#write2_pkey > input").value, sodium.base64_variants.ORIGINAL_NO_PADDING),
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1065
						function(success) {
1066
							if (success) {
1067
								console.log("Sent ok");
1068
							} else {
1069
								console.log("Failed sending");
1070
							}
1071
						}
1072
					);
1073
				break;
1074
			}
1075
		break;
1076
1077
		case TAB_NOTES:
1078
			for (let i = 0; i <= tabs[tab].max; i++) {
1079
				document.getElementById("div_notes").children[i].hidden = (i !== tabs[tab].cur);
1080
			}
1081
		break;
1082
1083
		case TAB_TOOLS:
1084
			for (let i = 0; i <= tabs[tab].max; i++) {
1085
				document.getElementById("div_tools").children[i].hidden = (i !== tabs[tab].cur);
1086
			}
1087
		break;
1088
	}
1089
1090
	document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
1091
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
1092
}
1093
1094
document.getElementById("btn_left").onclick = function() {
1095
	tabs[tab].cur--;
1096
	if (tabs[tab].cur === 0) this.disabled = true;
1097
	if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
1098
	updateTab();
1099
	this.blur();
1100
};
1101
1102
document.getElementById("btn_rght").onclick = function() {
1103
	tabs[tab].cur++;
1104
	if (tabs[tab].cur === tabs[tab].max) this.disabled = true;
1105
	document.getElementById("btn_left").disabled = false;
1106
	updateTab();
1107
	this.blur();
1108
};
1109
1110
const buttons = document.querySelector("#main1 > .top").getElementsByTagName("button");
1111
for (let i = 0; i < buttons.length; i++) {
1112
	buttons[i].onclick = function() {
1113
		tab = i;
1114
1115
		for (let j = 0; j < buttons.length; j++) {
1116
			document.querySelector("#main1 > .mid").children[j].hidden = (tab !== j);
1117
			buttons[j].disabled = (tab === j);
1118
		}
1119
1120
		document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
0 ignored issues
show
Bug introduced by
The variable tab is changed as part of the for loop for example by i on line 1113. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
1121
		document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
1122
		document.getElementById("btn_dele").disabled = !tabs[tab].btnDele;
1123
		document.getElementById("btn_updt").disabled = !tabs[tab].btnUpdt;
1124
	};
1125
}
1126
1127
function addressCreate(addr) {
1128
	const btnN = document.getElementById("btn_address_create_normal");
1129
	const btnS = document.getElementById("btn_address_create_shield");
1130
	btnN.disabled = true;
1131
	btnS.disabled = true;
1132
1133
	ae.Address_Create(addr, function(success1) {
1134
		if (success1) {
1135
			ae.Private_Update(function(success2) {
1136
				addAddress(ae.GetAddressCount() - 1);
1137
				if (addr !== "SHIELD") document.getElementById("txt_address_create_normal").value = "";
1138
				updateAddressCounts();
1139
1140
				if (!success2) console.log("Failed to update the Private field");
1141
1142
				if (ae.GetAddressCountNormal() < ae.GetLimitNormalA(ae.GetUserLevel())) btnN.disabled = false;
1143
				if (ae.GetAddressCountShield() < ae.GetLimitShieldA(ae.GetUserLevel())) btnS.disabled = false;
1144
			});
1145
		} else {
1146
			console.log("Failed to add address");
1147
1148
			if (ae.GetAddressCountNormal() < ae.GetLimitNormalA(ae.GetUserLevel())) btnN.disabled = false;
1149
			if (ae.GetAddressCountShield() < ae.GetLimitShieldA(ae.GetUserLevel())) btnS.disabled = false;
1150
		}
1151
	});
1152
}
1153
1154
document.getElementById("btn_address_create_normal").onclick = function() {
1155
	if (ae.GetAddressCountNormal() >= ae.GetLimitNormalA(ae.GetUserLevel())) return;
1156
1157
	const txtNewAddr = document.getElementById("txt_address_create_normal");
1158
	if (!txtNewAddr.reportValidity()) return;
1159
1160
	addressCreate(txtNewAddr.value);
1161
};
1162
1163
document.getElementById("btn_address_create_shield").onclick = function() {
1164
	if (ae.GetAddressCountShield() >= ae.GetLimitShieldA(ae.GetUserLevel())) return;
1165
1166
	addressCreate("SHIELD");
1167
};
1168
1169
document.getElementById("btn_address_update").onclick = function() {
1170
	const btn = this;
1171
	btn.disabled = true;
1172
1173
	const rows = document.getElementById("tbl_addrs").rows;
1174
1175
	for (let i = 0; i < rows.length; i++) {
1176
		ae.SetAddressAccExt(i, rows[i].getElementsByTagName("input")[0].checked);
1177
		ae.SetAddressAccInt(i, rows[i].getElementsByTagName("input")[1].checked);
1178
	}
1179
1180
	ae.Address_Update(function(success) {
1181
		if (!success) console.log("Address/Update failed");
1182
		btn.disabled = false;
1183
	});
1184
};
1185
1186
document.getElementById("btn_reg").onclick = function() {
1187
	const btn = document.getElementById("btn_reg");
1188
	const txt = document.getElementById("txt_reg");
1189
	if (!txt.reportValidity()) return;
1190
	btn.disabled = true;
1191
1192
	ae.Account_Create(txt.value, function(success) {
1193
		if (success) {
1194
			addAccountToTable(ae.Admin_GetUserCount() - 1);
1195
			txt.value = "";
1196
		}
1197
1198
		btn.disabled = false;
1199
	});
1200
};
1201
1202
document.getElementById("chk_downme").onclick = function() {document.getElementById("btn_downme").disabled = !this.checked;};
1203
document.getElementById("chk_killme").onclick = function() {document.getElementById("btn_killme").disabled = !this.checked;};
1204
1205
document.getElementById("btn_notepad_saveupl").onclick = function() {
1206
	const np = document.getElementById("txt_notepad");
1207
	np.disabled = true;
1208
1209
	let fname = prompt("Save as...", "Untitled");
0 ignored issues
show
Debugging Code Best Practice introduced by
The prompt UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1210
	if (!fname.endsWith(".txt")) fname += ".txt";
1211
1212
	ae.Message_Upload(fname, np.value, function(success) {
1213
		if (success) {
1214
			np.value = "";
1215
			addUploads();
1216
			document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
1217
		}
1218
1219
		console.log("Failed to add text");
1220
		np.disabled = false;
1221
	});
1222
};
1223
1224
document.getElementById("btn_upload").onclick = function() {
1225
	const btn = this;
1226
	const fileSelector = document.createElement("input");
1227
	fileSelector.type = "file";
1228
	fileSelector.click();
1229
1230
	fileSelector.onchange = function() {
1231
		btn.disabled = true;
1232
1233
		const reader = new FileReader();
1 ignored issue
show
Bug introduced by
The variable FileReader seems to be never declared. If this is a global, consider adding a /** global: FileReader */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1234
		reader.onload = function() {
1235
			ae.Message_Upload(fileSelector.files[0].name, new Uint8Array(reader.result), function(success) {
1236
				if (success) {
1237
					addUploads();
1238
					document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
1239
				} else {
1240
					console.log("Failed upload");
1241
				}
1242
1243
				btn.disabled = false;
1244
			});
1245
		};
1246
1247
		reader.readAsArrayBuffer(fileSelector.files[0]);
1248
	};
1249
};
1250
1251
document.getElementById("btn_pg").onclick = function() {
1252
	localStorage.greeting = document.getElementById("txt_pg").value;
1 ignored issue
show
Bug introduced by
The variable localStorage seems to be never declared. If this is a global, consider adding a /** global: localStorage */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1253
};
1254
1255
document.getElementById("txt_skey").onkeyup = function(event) {
1256
	if (event.key === "Enter") {
1257
		event.preventDefault();
1258
		document.getElementById("btn_enter").click();
1259
	}
1260
};
1261
1262
document.getElementById("btn_enter").onclick = function() {
1263
	const txtSkey = document.getElementById("txt_skey");
1264
	if (!txtSkey.reportValidity()) return;
1265
1266
	const btn = this;
1267
	btn.disabled = true;
1268
	document.getElementById("txt_skey").style.background = "#233";
1269
1270
	ae.SetKeys(txtSkey.value, function(successSetKeys) {
1271
		if (successSetKeys) {
1272
			ae.Message_Browse(false, true, function(successBrowse) {
1273
				if (successBrowse) {
1274
					txtSkey.value = "";
1275
					document.getElementById("div_begin").hidden = true;
1276
					document.getElementById("div_main").style.display = "grid";
1277
					reloadAccount();
1278
1279
					if (ae.IsUserAdmin()) {
1280
						ae.Account_Browse(function(successAcc) {
1281
							if (successAcc) {for (let i = 0; i < ae.Admin_GetUserCount(); i++) {addAccountToTable(i);}}
1282
							else console.log("Failed to Account_Browse");
1283
						});
1284
					}
1285
				} else {
1286
					console.log("Failed to enter");
1287
					btn.disabled = false;
1288
					document.getElementById("txt_skey").style.background = "#466";
1289
					txtSkey.focus();
1290
				}
1291
			});
1292
		} else {
1293
			console.log("Invalid format for key");
1294
			btn.disabled = false;
1295
			document.getElementById("txt_skey").style.background = "#466";
1296
			txtSkey.focus();
1297
		}
1298
	});
1299
};
1300
1301
});
1302